/* --------------------------------------------------------------------	*
 * mpi_demo.c															*
 * 																		*
 * A simple MPI demonstration program to evaluate an expression.		*
 * --------------------------------------------------------------------	*/
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>			/* for MPI constants and functions		*/

#define MSG_DATA		100		/* message from master to slaves		*/
#define MSG_RESULT		101		/* message from slave to master			*/

#define MASTER			0		/* rank of master						*/
#define SLAVE_1			1		/* rank of first slave					*/
#define SLAVE_2			2		/* rank of second slave					*/

/* functions to handle the tasks of master, and the two slaves			*/
void master(void);
void slave_1(void);
void slave_2(void);

int main(int argc, char** argv)
{
	int myrank, size;
	
	/* initialize the MPI system 										*/
	MPI_Init(&argc, &argv);

	/* get the size of the communicator i.e. number of processes		*/
	MPI_Comm_size(MPI_COMM_WORLD, &size);

	/* check for proper number of processes								*/
	if(size != 3)
	{
		fprintf(stderr, "Error: Three copies of the program should be run.\n");
		MPI_Finalize();
		exit(EXIT_FAILURE);
	}
	
	/* get the rank of the process										*/
	MPI_Comm_rank(MPI_COMM_WORLD, &myrank);

	/* perform the tasks according to the rank							*/
	if(myrank == MASTER)
		master();
	else if(myrank == SLAVE_1)
		slave_1();
	else
		slave_2();

	/* clean up and exit from the MPI system							*/
	MPI_Finalize();

	exit(EXIT_SUCCESS);
} /* end main() */

/* function to carry out the masters tasks			*/
void master(void)
{
	int a, b, c, d;
	int buf[2];
	int result1, result2;
	MPI_Status status;

	printf("Enter the values of a, b, c, and d: ");
	scanf("%d %d %d %d", &a, &b, &c, &d);

	/* send a and b to the first slave				*/
	buf[0] = a;
	buf[1] = b;
	MPI_Send(buf, 2, MPI_INT, SLAVE_1, MSG_DATA, MPI_COMM_WORLD);

	/* send c and d to the secons slave				*/
	buf[0] = c;
	buf[1] = d;
	MPI_Send(buf, 2, MPI_INT, SLAVE_2, MSG_DATA, MPI_COMM_WORLD);

	/* receive results from the slaves				*/
	MPI_Recv(&result1, 1, MPI_INT, SLAVE_1, MSG_RESULT, 
			 MPI_COMM_WORLD, &status);
	MPI_Recv(&result2, 1, MPI_INT, SLAVE_2, MSG_RESULT, 
			 MPI_COMM_WORLD, &status);

	/* final result									*/
	printf("Value of (a + b) * (c - d) is %d\n", result1 * result2);
} /* end master() */

/* function to carry out the tasks of the first slave		*/
void slave_1(void)
{
	int buf[2];
	int result;
	MPI_Status status;
	
	/* receive the two values from the master		*/ 
	MPI_Recv(buf, 2, MPI_INT, MASTER, MSG_DATA, MPI_COMM_WORLD, &status);
	
	/* find a + b									*/
	result = buf[0] + buf[1];

	/* send result to the master					*/
	MPI_Send(&result, 1, MPI_INT, MASTER, MSG_RESULT, MPI_COMM_WORLD);
} /* end slave_1() */

/* function to carry out the tasks of the second slave		*/
void slave_2(void)
{
	int buf[2];
	int result;
	MPI_Status status;
	
	/* receive the two values from the master		*/
	MPI_Recv(buf, 2, MPI_INT, MASTER, MSG_DATA, MPI_COMM_WORLD, &status);
	
	/* find c - d									*/
	result = buf[0] - buf[1];

	/* send result to master						*/
	MPI_Send(&result, 1, MPI_INT, MASTER, MSG_RESULT, MPI_COMM_WORLD);
} /* end slave_2() */

/* end mpi_demo.c */
